package main

import (
	"context"
	"time"

	"github.com/filecoin-project/specs-storage/storage"
)

const defaultManageLockTTl = 60 * time.Second

// Commit2Data c2 data
type Commit2Data struct {
	*Commit2Request
	ReturnChan chan storage.Proof
}

// Manager 任务调度
type Manager struct {
	locker   *Locker
	taskChan chan *Commit2Data
	ctx      context.Context
}

func NewManager(ctx context.Context, client RedisClient) *Manager {
	return &Manager{
		ctx:      ctx,
		locker:   NewLocker(ctx, client, "manage:lock"),
		taskChan: make(chan *Commit2Data),
	}
}

// Schedule 调度
func (m *Manager) Schedule(task *Commit2Data) {
	t := time.NewTicker(time.Duration(time.Second * 10))
	defer t.Stop()
	for {

		select {
		case <-t.C: //
			if m.Lock() {
				defer m.Unlock()
				// 获取所有service
				all, err := AllServices()
				if err != nil {
					log.Warn("获取所有服务失败：err %s", err)
					task.ReturnChan <- storage.Proof{}
					return
				}
				log.Infof("调度 %s,%s ", task.SectorID.Number, task.SectorID.Miner)

				for _, service := range all {
					num := service.HasAbleTaskNum()
					if num > 0 && service.AddTaskNum(1) { // 有资源可以执行任务

						defer service.AddTaskNum(-1)

						rs, err := service.C2(task.Commit2Request)
						if err != nil {
							task.ReturnChan <- storage.Proof{}
						} else {
							task.ReturnChan <- rs
						}
						return
					}
				}
			} else {
				// 没有拿到锁返回空字符
				log.Warn("获取锁失败：sector %s minerID %s", task.SectorID.Number, task.SectorID.Miner)
				task.ReturnChan <- storage.Proof{}
				return
			}
		case <-time.After(time.Hour * 10): //超过10小时退出
			return

		case <-m.ctx.Done():
			m.Close()
			return
		}
	}

}

func (m *Manager) Run() {
	for {
		select {
		case task := <-m.taskChan:
			go m.Schedule(task)

		case <-m.ctx.Done():
			m.Close()
			return
		}
	}
}

func (m *Manager) Lock() bool {
	t := time.NewTicker(time.Duration(time.Microsecond * 5))
	defer t.Stop()
	for {
		select {
		case <-t.C:
			if m.locker.Lock(defaultManageLockTTl) {
				return true
			}
		case <-time.After(time.Hour * 10): //超过10小时退出
			return false
		case <-m.ctx.Done():
			return false
		}
	}
}

func (m *Manager) Unlock() error {
	return m.locker.Unlock()
}

func (m *Manager) Close() {
	m.locker.Unlock()
}
